from datetime import datetime
from django.shortcuts import render, redirect

from core.utils.response import Result
from .utils.disease_response import  DiseaseResponse
from .forms import UploadForm
from .utils.process_wav import process_audio_files, get_prediction_dict
import json
import logging
import os
from django.contrib.auth.decorators import login_required
from django.contrib import messages
# from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import DiagnosisHistory
from django.core.cache import cache
from django.views.decorators.http import require_POST,require_GET
from django.contrib.auth.models import User


logger = logging.getLogger(__name__)

# Create your views here.

# 静默分割合并
# def  interval_remove(wav_data):
#     pass

RATE_LIMIT = 3 * 3  # 每分钟最多允许的请求数(每次要3次request)

def rate_limit(view_func):
    
    def _wrapped_view(request, *args, **kwargs):
        user_ip = request.META.get('REMOTE_ADDR') # 获取用户IP remote address
        cache_key = f"rate_limit_{user_ip}" # 以用户IP为key
        request_count = cache.get(cache_key, 0) # 获取当前请求次数
        logging.info(f"当前用户,ip:{user_ip}访问次数为{request_count}")
        
        if request_count >= RATE_LIMIT: # 如果请求次数超过限制
            # raise PermissionDenied("请求过于频繁，请稍后再试。")
            return Result.error(message="请求过于频繁，请稍后再试。")
            # return JsonResponse({"message":"请求过于频繁，请稍后再试。"},status=400)
        
        cache.set(cache_key, request_count + 1, timeout=60) # 60秒内只允许请求RATE_LIMIT次 60s后刷新
        return view_func(request, *args, **kwargs)
    
    return _wrapped_view

def save_diagnosis(user, diagnosis_result, prediction_rate, notes=""):
    """保存诊断结果到数据库"""
    DiagnosisHistory.objects.create(
        user=user,
        diagnosis_result=diagnosis_result,
        prediction_rates=prediction_rate,  # json 字段
        notes=notes,
    )


@csrf_exempt
@require_GET # 只接受GET请求
def get_diagnosis_history(request):
    # 1.从header获取openid
    logger.info("get_diagnosis_history",request.headers)
    openid = request.headers.get("openid", "")
    # 2.从数据库获取用户的诊断历史（从外键user对象的属性username 判断）
    diagnosisHistory = DiagnosisHistory.objects.filter(user__username="微信小程序用户_" + openid) # 要返回DiagnosisHistory对象
    # diagnosisHistory = DiagnosisHistory.objects.filter(user__username=prefix_openid) # 穿过去的时候已经是添加了前缀了
    # 3.返回值（需要对每一个history的数据再次进行封装）
    if not diagnosisHistory:
        return Result.error(message="未找到诊断历史")
    diagnosisHistory_dict = [DiseaseResponse.create_from_diagnosis_history(histroy) for histroy in diagnosisHistory] 
    return Result.success(data={"diagnosisHistory": diagnosisHistory_dict})
    
    
@csrf_exempt
@require_POST # 只接受POST请求(无需判断)
@rate_limit
def predict(request): 
    # App支持多文件上传，微信小程序只支持单文件上传，传多个文件需要反复调用本API。所以跨端的写法就是循环调用本API。
    # 故用session_id作为标识，缓存每个session的文件，当收到所有文件后再处理
    session_id = request.POST.get("sessionId")
    prefix_openid = request.POST.get("prefix_openid")
    
    # 使用更规范的日志格式
    logger.info(f"session_id: {session_id}" if session_id else "session_id: None")
    logger.info(f"prefix_openid: {prefix_openid}" if prefix_openid else "prefix_openid: None")
    
    if not session_id:  # 微信小程序端上传 需要session_id
        logger.warning("缺少 session_id")
        return Result.error(message="缺少 session_id")
    if not prefix_openid:  # 微信小程序端上传 需要code
        logger.warning("缺少 prefix_openid")
        return Result.error(message="缺少 prefix_openid")

    # 使用缓存操作（移除了线程锁，因为LocMemCache不支持）
    cached_files = cache.get(session_id, {})
    audio_types = ["cough_file", "breath_file", "speech_file"]

    # 获取当前请求的文件
    current_file = None
    current_type = None
    for audio_type in audio_types:
        file_obj = request.FILES.get(audio_type)
        if file_obj:
            current_file = file_obj
            current_type = audio_type
            break

    if not current_file:
        logger.warning("未收到任何有效文件")
        return Result.error(message="未收到任何有效文件")

    # 更新缓存
    cached_files[current_type] = current_file
    cache.set(session_id, cached_files, timeout=300)  # 缓存5分钟
    
    # 添加详细日志记录缓存状态
    logger.info(f"当前session_id: {session_id}, 已缓存文件类型: {list(cached_files.keys())}")

    # 判断是否已收到所有文件
    if all(t in cached_files for t in audio_types):
        logger.info(f"已收到全部文件: {cached_files.keys()}")
        try:
            user_data = process_audio_files(
                type("request", (object,), {"FILES": cached_files})
            )
            response = get_prediction_dict(user_data)
            cache.delete(session_id)  # 处理完后删除缓存
            
            user = User.objects.get(username=prefix_openid)
            save_diagnosis(
                user=user, 
                diagnosis_result=response["diagnosis_result"], 
                prediction_rate=response["prediction_rate"],
                notes="微信小程序端上传"
            )
            return Result.success(response)
        except Exception as e:
            logger.error(f"处理文件时发生错误: {str(e)}", exc_info=True)
            return Result.error(message="处理文件时发生错误")
    
    return Result.error(400, "waiting for other files")


@login_required(login_url="/accounts/login/")
def upload_audio(request):
    if request.method == "POST":
        # form = UploadForm(request.POST, request.FILES)
        # if form.is_valid(): # 后端不需要验证 前端验证好了
        user_data = process_audio_files(request)
        response = get_prediction_dict(user_data)
        logger.info(response)
        save_diagnosis(
            user=request.user,
            diagnosis_result=response["diagnosis_result"],
            prediction_rate=response["prediction_rate"],
        )
        # Handle the response as needed
        messages.success(request, "诊断成功！")
        return render(
            request, "disease_recognition/disease.html", {"context": response}
        )
    else:
        form = UploadForm()
        # response = {"covid_19": None, "healthy": None, "asthma": None}
        return render(
            request,
            "disease_recognition/upload_audio.html",
            {"form": form},
            # {"form": form, "context": response},
        )


@login_required(login_url="/accounts/login/")
def history_index(request):
    diagnosis_histories = DiagnosisHistory.objects.filter(user=request.user).order_by(
        "-diagnosis_date"
    )  # 按时间倒序排序（默认就是，也可以不用这个代码）
    # diagnosis_histories_dict = [
    #     DiseaseResponse.create_from_diagnosis_history(histroy) for histroy in diagnosis_histories]
    logger.info(diagnosis_histories)
    # 其中 prediction_rates 字段是JSONField类型，可以直接使用字典的方式进行查询
    return render(
        request,
        "disease_recognition/history_index.html",
        {"diagnosis_histories": diagnosis_histories},
    )


@login_required(login_url="/accounts/login/")
def history_detail(request, id):
    # diagnosis_id = request.GET.get("id") # 路由传参
    diagnosis = DiagnosisHistory.objects.get(id=id)
    logger.info("查询单条历史记录：",diagnosis)
    if diagnosis.diagnosis_result.strip() == "可能存在其他呼吸道疾病": 
        context = DiseaseResponse.create_other_disease(diagnosis.prediction_rates)
        # context = DiseaseResponse.create_other_disease(diagnosis.get('prediction_rates', []))
    else:
        context = DiseaseResponse.create_from_diagnosis_history(diagnosis)
    return render(request, "disease_recognition/disease.html", {"context": context})


@login_required(login_url="/accounts/login/")
def history_detail_add_note(request, id):
    # diagnosis_id = request.GET.get("id") # 只能直接从参数获取，否则报错
    if request.method == "POST":
        diagnosis = DiagnosisHistory.objects.get(id=id)
        note = request.POST.get("note")
        logger.info("id" + "添加备注:" + note)
        diagnosis.notes = note
        diagnosis.save()  # 保存到数据库
        # 这个是django自带的消息框 用于提示用户 django.contrib.messages as Bootstrap alerts (info, success, warning, error)
        # 如果用vue 则可以用element-ui的message组件
        messages.success(request, "添加备注成功！")
        return redirect("disease_recognition:history_index")
